home *** CD-ROM | disk | FTP | other *** search
- //////////
- //
- // File: QTFrameStepper.c
- //
- // Contains: Functions to step frame-by-frame through a QuickTime movie.
- //
- // Written by: Tim Monroe
- // Parts based on DTSQTUtilities.c by Apple Developer Technical Support
- // and on SimpleInMovies sample code by Guillermo A. Ortiz.
- //
- // Copyright: © 1997 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <5> 11/18/98 rtm added QTStep_GetFrameCount, for illustrative purposes only
- // <4> 03/09/98 rtm changed nextTimeMediaSample flag to nextTimeStep (to support MPEG files)
- // <3> 01/05/98 rtm revised and augmented comments
- // <2> 01/02/98 rtm some code clean-up
- // <1> 12/22/97 rtm first file
- //
- // This file defines functions that you can use to step frame-by-frame through a QuickTime movie.
- // Indeed, it illustrates *two* different methods for doing this: (1) using Movie Toolbox functions
- // to advance (or retreat) to interesting times in the movie; and (2) using movie controller actions
- // to step forward or backward through a movie. To my knowledge, there are no particular advantages
- // to using one or the other method, except that the second method is (as you will see) quite a bit
- // simpler to code.
- //
- // METHOD ONE: Use Movie Toolbox calls to step to interesting times in the movie. An interesting time
- // is a time value in a movie, track, or media that meets certain search conditions that you specify.
- // We'll use a very simple search condition: locate the next (or previous) sample in the movie's media.
- // Once we have an interesting time, we display the sample at that time by calling SetMovieTimeValue.
- // To implement this first method, we define three functions (which all operate on an open movie):
- //
- // -> QTStep_GoToNextVideoSample: display the sample that follows the current sample in a movie
- // -> QTStep_GoToPrevVideoSample: display the sample that precedes the current sample in a movie
- // -> QTStep_GoToFirstVideoSample: display the first video sample in a movie
- //
- // Internally, these functions depend on three static functions defined at the beginning of this file.
- // The code here is extremely straightforward. The only "gotcha" concerns finding the first
- // interesting time in a movie. See the description of QTStep_GetStartTimeOfFirstVideoSample for
- // details.
- //
- // METHOD TWO: Use movie controller actions to step through frames in the movie. This method uses
- // the MCDoAction function with the mcActionStep and mcActionGoToTime actions. Using this method,
- // the code is considerably simpler. To implement this second method, we define three functions
- // (which all operate on a movie controller that is associated with an open movie):
- //
- // -> QTStep_MCGoToNextVideoSample: display the sample that follows the current sample in a movie
- // -> QTStep_MCGoToPrevVideoSample: display the sample that precedes the current sample in a movie
- // -> QTStep_MCGoToFirstVideoSample: display the first video sample in a movie
- //
- // Historical note: Method One is based loosely on sample-stepping code in the DTSQTUtilities package
- // developed by Apple Macintosh Developer Technical Support. Method Two is based on a few functions
- // in the SimpleInMovies sample code written by Guillermo A. Ortiz.
- //
- //////////
-
- #include "QTFrameStepper.h"
-
-
- //////////
- //
- // METHOD ONE: Use Movie Toolbox calls to step to interesting times in the movie.
- //
- //////////
-
- //////////
- //
- // QTStep_GetStartTimeOfFirstVideoSample
- // Return, through the theTime parameter, the starting time of the first video sample of the
- // specified QuickTime movie.
- //
- // The "trick" here is to set the nextTimeEdgeOK flag, to indicate that you want to get the
- // starting time of the beginning of the movie.
- //
- // If this function encounters an error, it returns a (bogus) starting time of -1. Note that
- // GetMovieNextInterestingTime also returns -1 as a starting time if the search criteria
- // specified in the myFlags parameter are not matched by any interesting time in the movie.
- //
- //////////
-
- static OSErr QTStep_GetStartTimeOfFirstVideoSample (Movie theMovie, TimeValue *theTime)
- {
- short myFlags;
- OSType myTypes[1];
-
- *theTime = kBogusStartingTime; // a bogus starting time
- if (theMovie == NULL)
- return(invalidMovie);
-
- myFlags = nextTimeMediaSample + nextTimeEdgeOK; // we want the first sample in the movie
- myTypes[0] = VisualMediaCharacteristic; // we want video samples
-
- GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, (TimeValue)0, fixed1, theTime, NULL);
- return(GetMoviesError());
- }
-
-
- //////////
- //
- // QTStep_DrawVideoSampleAtTime
- // Draw the video sample of a QuickTime movie at the specified time.
- //
- //////////
-
- static OSErr QTStep_DrawVideoSampleAtTime (Movie theMovie, TimeValue theTime)
- {
- short myFlags;
- OSErr myErr = noErr;
-
- if (theMovie == NULL)
- return(invalidMovie);
-
- // make sure that the specified time lies within the movie's temporal bounds
- if ((theTime < 0) || (theTime > GetMovieDuration(theMovie)))
- return(paramErr);
-
- SetMovieTimeValue(theMovie, theTime);
- myErr = GetMoviesError();
- if (myErr != noErr)
- goto bail;
-
- // the following calls to UpdateMovie and MoviesTask are not necessary
- // if you are handling movie controller events in your main event loop
- // (by passing the event to MCIsPlayerEvent); they don't hurt, however.
-
- // redraw the movie immediately by calling UpdateMovie and MoviesTask
- UpdateMovie(theMovie);
- myErr = GetMoviesError();
- if (myErr != noErr)
- goto bail;
-
- MoviesTask(theMovie, 0L);
- myErr = GetMoviesError();
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // QTStep_DrawVideoSampleNextOrPrev
- // Draw the next or previous video sample of a QuickTime movie.
- // If theRate is 1, the next video sample is drawn; if theRate is -1, the previous sample is drawn.
- //
- //////////
-
- static OSErr QTStep_DrawVideoSampleNextOrPrev (Movie theMovie, Fixed theRate)
- {
- TimeValue myCurrTime;
- TimeValue myNextTime;
- short myFlags;
- OSType myTypes[1];
- OSErr myErr = noErr;
-
- if (theMovie == NULL)
- return(invalidMovie);
-
- myFlags = nextTimeStep; // we want the next frame in the movie's media
- myTypes[0] = VisualMediaCharacteristic; // we want video samples
- myCurrTime = GetMovieTime(theMovie, NULL);
-
- GetMovieNextInterestingTime(theMovie, myFlags, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL);
- myErr = GetMoviesError();
- if (myErr != noErr)
- return(myErr);
-
- myErr = QTStep_DrawVideoSampleAtTime(theMovie, myNextTime);
-
- return(myErr);
- }
-
-
- //////////
- //
- // QTStep_GoToFirstVideoSample
- // Draw the first video sample of a QuickTime movie.
- //
- //////////
-
- OSErr QTStep_GoToFirstVideoSample (Movie theMovie)
- {
- TimeValue myTime;
- OSErr myErr = noErr;
-
- if (theMovie == NULL)
- return(invalidMovie);
-
- myErr = QTStep_GetStartTimeOfFirstVideoSample(theMovie, &myTime);
- if (myErr != noErr)
- return(myErr);
-
- myErr = QTStep_DrawVideoSampleAtTime(theMovie, myTime);
- return(myErr);
- }
-
-
- //////////
- //
- // QTStep_GoToNextVideoSample
- // Draw the next video sample of a QuickTime movie.
- //
- //////////
-
- OSErr QTStep_GoToNextVideoSample (Movie theMovie)
- {
- return(QTStep_DrawVideoSampleNextOrPrev(theMovie, fixed1));
- }
-
-
- //////////
- //
- // QTStep_GoToPrevVideoSample
- // Draw the previous video sample of a QuickTime movie.
- //
- //////////
-
- OSErr QTStep_GoToPrevVideoSample (Movie theMovie)
- {
- return(QTStep_DrawVideoSampleNextOrPrev(theMovie, FixMul(Long2Fix(-1), fixed1)));
- }
-
-
- //////////
- //
- // METHOD TWO: Use movie controller actions to step thru frames in the movie.
- //
- //////////
-
- //////////
- //
- // QTStep_MCGoToFirstVideoSample
- // Draw the first video sample of the QuickTime movie associated with the specified movie controller.
- //
- //////////
-
- OSErr QTStep_MCGoToFirstVideoSample (MovieController theMC)
- {
- TimeRecord myTimeRecord;
- Movie myMovie = NULL;
- OSErr myErr = noErr;
-
- if (theMC == NULL)
- return(paramErr);
-
- myMovie = MCGetMovie(theMC);
- if (myMovie == NULL)
- return(paramErr);
-
- myTimeRecord.value.hi = 0;
- myTimeRecord.value.lo = 0;
- myTimeRecord.base = 0;
- myTimeRecord.scale = GetMovieTimeScale(myMovie);
- myErr = GetMoviesError();
- if (myErr != noErr)
- return(myErr);
-
- return(MCDoAction(theMC, mcActionGoToTime, &myTimeRecord));
- }
-
-
- //////////
- //
- // QTStep_MCGoToNextVideoSample
- // Draw the next video sample of the QuickTime movie associated with the specified movie controller.
- //
- //////////
-
- OSErr QTStep_MCGoToNextVideoSample (MovieController theMC)
- {
- short myStep = 1; // advance the movie one frame
-
- if (theMC == NULL)
- return(paramErr);
-
- return(MCDoAction(theMC, mcActionStep, (Ptr)myStep));
- }
-
-
- //////////
- //
- // QTStep_MCGoToPrevVideoSample
- // Draw the previous video sample of the QuickTime movie associated with the specified movie controller.
- //
- //////////
-
- OSErr QTStep_MCGoToPrevVideoSample (MovieController theMC)
- {
- short myStep = -1; // back the movie up one frame
-
- if (theMC == NULL)
- return(paramErr);
-
- return(MCDoAction(theMC, mcActionStep, (Ptr)myStep));
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Frame utilities.
- //
- // These functions illustrate some other useful things you might want to do with movie frames;
- // they are not used elsewhere in this file.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // QTStep_GetFrameCount
- // Get the number of frames in the specified movie track. We return the value -1 if
- // an error occurs and we cannot determine the number of frames in the track.
- //
- // Based (loosely) on frame-counting code in ConvertToMovie Jr.c.
- //
- // We count the frames in the track by stepping through all of its interesting times
- // (the places where the track displays a new sample).
- //
- //////////
-
- long QTStep_GetFrameCount (Track theTrack)
- {
- long myCount = -1;
- short myFlags;
- TimeValue myTime = 0;
-
- if (theTrack == NULL)
- goto bail;
-
- // we want to begin with the first frame (sample) in the track
- myFlags = nextTimeMediaSample + nextTimeEdgeOK;
-
- while (myTime >= 0) {
- myCount++;
-
- // look for the next frame in the track; when there are no more frames,
- // myTime is set to -1, so we'll exit the while loop
- GetTrackNextInterestingTime(theTrack, myFlags, myTime, fixed1, &myTime, NULL);
-
- // after the first interesting time, don't include the time we're currently at
- myFlags = nextTimeStep;
- }
-
- bail:
- return(myCount);
- }
-
-
-